package com.zf.rabbitmq.producer.declare_type;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 使用 Bean 的方式声明 交换机、队列、绑定：
 * - org.springframework.amqp.core.Exchange
 * - org.springframework.amqp.core.Queue
 * - org.springframework.amqp.core.Binding
 * 创建对应的bean即可声明 交换机、队列、绑定时 。
 * <p>
 * 本质还是调用 AmqpAdmin（实际是RabbitAdmin对象） 中的 declare* 开头的方法来声明 交换机、队列、绑定
 * <p>
 * 使用 Bean 的方式声明，会在容器产生bean，如果用不到就是浪费空间
 * <p>
 * 详见 README.md
 */
@Configuration
public class DeclareExchangeQueueBindingByBean {
    public static final String testBeanQueueName = "test_bean_queue";
    public static final String testBeanDirectExchangeName = "test_bean_direct_exchange";
    public static final String testBeanRouteKey = "test_bean_route_key";

    /**
     * 声明一个 队列，如果已经存在则校验参数是否一致，不一致就报错，如果不存在就创建队列
     */
    @Bean
    public Queue testBeanQueue() {
        // 方法1：使用 new Queue() 声明一个 队列，不设置参数，
        // Queue中有个actualName属性，如果队列名称是 空字符串 或者 null, spring会自动生成一个队列名称，并赋值给 该属性，
        // 如果队列名不空则直接把队列名赋值给actualName
        // Queue中有个name属性存放传入的队列名，传入的什么就是什么
        return new Queue(testBeanQueueName, true, false, false, null);

        // 方法2：使用 QueueBuilder 声明队列
        // Queue queue = QueueBuilder.durable("test_bean_queue")
        //         .deadLetterExchange("")
        //         .deadLetterRoutingKey("")
        //         .build();
    }

    /**
     * 声明一个交换机，如果已经存在则校验参数是否一致，不一致就报错，如果不存在就创建交换机
     */
    @Bean
    public Exchange testBeanExchange() {
        // 方法1：使用 new 方法 声明一个 direct 类型的交换机 ，不设置参数
        return new DirectExchange(testBeanDirectExchangeName, true, false, null);
        // return new TopicExchange("sb_bean_direct_exchange", true, false, null);
        // return new FanoutExchange("sb_bean_direct_exchange", true, false, null);
        // return new HeadersExchange("sb_bean_direct_exchange", true, false, null);

        // 方法2：或者手动指定交换机类型
        // return new CustomExchange("sb_bean_direct_exchange", ExchangeTypes.DIRECT,  true, false, null);

        // 方法3：使用 ExchangeBuilder 声明交换机
        // Exchange exchange = ExchangeBuilder.directExchange("test_bean_direct_exchange")
        //         .durable(true)
        //         .withArguments(null)
        //         .build();
    }

    /**
     * 声明一个绑定，如果已经存在则校验参数是否一致，不一致就创建新的绑定，如果不存在就创建绑定：
     * 用来绑定交换机和队列
     */
    @Bean
    public Binding testBeanBinding() {
        // 方法1：使用 BindingBuilder 声明一个绑定，bind(被绑定的队列或者交换机)， to(绑定到哪个队列上)，with(路由键)，and(绑定时的参数)
        // 此方式此等使用的依然是 方式2
        // Binding binding = BindingBuilder.bind(sbBeanQueue()).to(sbBeanExchange()).with("sb_bean_route_key").and(null);

        /*
        方法2：使用 new Binding() 声明绑定：
        public Binding(String destination, DestinationType destinationType, String exchange, String routingKey, Map<String, Object> arguments)：
            - destination： 被绑定的队列或者交换机
            - destinationType： destination类型，队列或者交换机
            - exchange：绑定到哪个交换机上
            - routingKey：路由键
            - arguments：绑定时的参数
         */
        Binding binding = new Binding(testBeanQueue().getName(), Binding.DestinationType.QUEUE, testBeanExchange().getName(), testBeanRouteKey, null);
        return binding;
    }
}
